// import com.alibaba.druid.DbType;
// import com.alibaba.druid.sql.ast.SQLCommentHint;
// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
// import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.List;

#include "MySqlInsertStatement.h"
#include "../../../../visitor/SQLASTVisitor.h"
#include "../../visitor/MySqlASTVisitor.h"
#include "../../../../../utils/instanceof.h"
#include "../../../../ast/statement/SQLExprTableSource.h"
#include "../../../../ast/statement/SQLSelect.h"

MySqlInsertStatement::MySqlInsertStatement()
{
  dbType = DbType_ptr(new DbType(&DbType::mysql));
  hints = std::make_shared<std::list<SQLCommentHint_ptr>>();
  duplicateKeyUpdate = std::make_shared<std::list<SQLExpr_ptr>>();
}

void MySqlInsertStatement::cloneTo(MySqlInsertStatement_ptr x)
{
  SQLInsertStatement::cloneTo(x);
  x->lowPriority = lowPriority;
  x->delayed = delayed;
  x->highPriority = highPriority;
  x->ignore = ignore;
  x->rollbackOnFail = rollbackOnFail;
  x->fulltextDictionary = fulltextDictionary;
  x->overwrite = overwrite;
  x->ifNotExists = ifNotExists;

  for (SQLExpr_ptr e : *duplicateKeyUpdate)
  {
    SQLExpr_ptr e2 = std::dynamic_pointer_cast<SQLExpr>(e->clone());
    e2->setParent(x);
    x->duplicateKeyUpdate->push_back(e2);
  }
}

SQLExpr_list_ptr MySqlInsertStatement::getDuplicateKeyUpdate()
{
  return duplicateKeyUpdate;
}

BOOL_ptr MySqlInsertStatement::isLowPriority()
{
  return lowPriority;
}

void MySqlInsertStatement::setLowPriority(BOOL_ptr lowPriority)
{
  this->lowPriority = lowPriority;
}

BOOL_ptr MySqlInsertStatement::isDelayed()
{
  return delayed;
}

void MySqlInsertStatement::setDelayed(BOOL_ptr delayed)
{
  this->delayed = delayed;
}

BOOL_ptr MySqlInsertStatement::isHighPriority()
{
  return highPriority;
}

void MySqlInsertStatement::setHighPriority(BOOL_ptr highPriority)
{
  this->highPriority = highPriority;
}

BOOL_ptr MySqlInsertStatement::isIgnore()
{
  return ignore;
}

void MySqlInsertStatement::setIgnore(BOOL_ptr ignore)
{
  this->ignore = ignore;
}

BOOL_ptr MySqlInsertStatement::isRollbackOnFail()
{
  return rollbackOnFail;
}

void MySqlInsertStatement::setRollbackOnFail(BOOL_ptr rollbackOnFail)
{
  this->rollbackOnFail = rollbackOnFail;
}

BOOL_ptr MySqlInsertStatement::isFulltextDictionary()
{
  return fulltextDictionary;
}

void MySqlInsertStatement::setFulltextDictionary(BOOL_ptr fulltextDictionary)
{
  this->fulltextDictionary = fulltextDictionary;
}

BOOL_ptr MySqlInsertStatement::isIfNotExists()
{
  return ifNotExists;
}

void MySqlInsertStatement::setIfNotExists(BOOL_ptr ifNotExists)
{
  this->ifNotExists = ifNotExists;
}

// @Override
void MySqlInsertStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (instanceof <SQLASTVisitor, MySqlASTVisitor>(visitor))
  {
    accept0(std::dynamic_pointer_cast<MySqlASTVisitor>(visitor));
  }
  else
  {
    SQLInsertStatement::accept0(visitor);
  }
}

void MySqlInsertStatement::accept0(MySqlASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(MySqlInsertStatement)))
  {
    if (tableSource != nullptr)
    {
      tableSource->accept(visitor);
    }

    if (columns != nullptr)
    {
      for (SQLExpr_ptr column : *columns)
      {
        if (column != nullptr)
        {
          column->accept(visitor);
        }
      }
    }

    if (valuesList != nullptr)
    {
      for (SQLInsertStatement_ValuesClause_ptr values : *valuesList)
      {
        if (values != nullptr)
        {
          values->accept(visitor);
        }
      }
    }

    if (query != nullptr)
    {
      query->accept(visitor);
    }

    if (duplicateKeyUpdate != nullptr)
    {
      for (SQLExpr_ptr item : *duplicateKeyUpdate)
      {
        if (item != nullptr)
        {
          item->accept(visitor);
        }
      }
    }
  }

  visitor->endVisit(SharedObject(MySqlInsertStatement));
}

int MySqlInsertStatement::getHintsSize()
{
  if (hints == nullptr)
  {
    return 0;
  }
  return hints->size();
}

SQLCommentHint_list_ptr MySqlInsertStatement::getHints()
{
  return hints;
}

void MySqlInsertStatement::setHints(SQLCommentHint_list_ptr x)
{
  if (x != nullptr)
  {
    auto it_x = x->begin();
    for (int i = 0; i < x->size(); i++)
    {
      std::advance(it_x, i);
      (*it_x)->SQLObjectImpl::setParent(SharedObject(MySqlInsertStatement));
    }
  }
  this->hints = x;
}

SQLObject_ptr MySqlInsertStatement::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<MySqlInsertStatement>(new MySqlInsertStatement());
  std::shared_ptr<MySqlInsertStatement> x = std::dynamic_pointer_cast<MySqlInsertStatement>(clone_tmp);
  // MySqlInsertStatement x = new MySqlInsertStatement();
  cloneTo(x);
  return x;
}

// @Override
BOOL_ptr MySqlInsertStatement::isOverwrite()
{
  return overwrite;
}

// @Override
void MySqlInsertStatement::setOverwrite(BOOL_ptr overwrite)
{
  this->overwrite = overwrite;
}
